# %%

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# %%

# 读取数据
train = pd.read_csv("data/railway_okzhuanginfo_去尾.csv")
# 删掉指定的非数据列
train = train.drop(['id', 'ZhuangNum', 'ProjectID', 'Starttime', 'Endtime', 'DeviceNum', 'State']
                   , axis=1)
train.head(3)

# %%  缺失值比率（Missing Value Ratio）

# 检查每个变量中缺失值的百分比。若不为0，则有缺失
train.isnull().sum() / len(train) * 100

# %%

# 在变量中保存缺失值(百分比)
a = train.isnull().sum() / len(train) * 100

# 在变量中保存小于阈值的列名
variables = train.columns
variable = []
for i in range(0, len(variables)):
    if a[i] <= 20:  # 设置阈值为20%,小于20的保留
        variable.append(variables[i])

# %% == 低方差滤波（Low Variance Filter） ==================================================
'''
如果我们有一个数据集，其中某列的数值基本一致，也就是它的方差非常低，那么这个变量还有价值吗？
和上一种方法的思路一致，我们通常认为低方差变量携带的信息量也很少，所以可以把它直接删除。
放到实践中，就是先计算所有变量的方差大小，然后删去其中最小的几个。
需要注意的一点是：方差与数据范围相关的，因此在采用该方法前需要对数据做归一化处理。
'''
# 放在示例中，我们先填上缺失值：
'''
让我们首先使用已知 Upspeed 观测值的中值来估算 Upspeed 列中的缺失值。
对于 Incurrent 列，我们将使用已知 Incurrent 值的众数来估算缺失值：
'''
train['Upspeed'].fillna(train['Upspeed'].median(), inplace=True)
train['DownSpeed'].fillna(train['DownSpeed'].median(), inplace=True)
train['Incurrent'].fillna(train['Incurrent'].mode()[0], inplace=True)
train['OutCurrent'].fillna(train['OutCurrent'].mode()[0], inplace=True)

# 检查缺失值是否已经被填充：
train.isnull().sum() / len(train) * 100

# 再计算所有数值变量的方差：
train.var()  # 此时获得高相关变量 OutCurrent (最高方差)

# %%

# 如上图所示，和其他变量相比，Lon的方差非常小，因此可以把它直接删除。
numeric = train
var = numeric.var()
numeric = numeric.columns
need_drop_col = []

for i in range(0, len(var)):
    if var[i] < 10:  # 将阈值设置为10％
        need_drop_col.append(numeric[i])

print(need_drop_col)

train.drop(need_drop_col, axis=1, inplace=True)

# %% == 高相关滤波（High Correlation filter）===============================================

'''
如果两个变量之间是高度相关的，这意味着它们具有相似的趋势并且可能携带类似的信息。
同理，这类变量的存在会降低某些模型的性能（例如线性和逻辑回归模型）。为了解决这个问题，
我们可以计算独立数值变量之间的相关性。如果相关系数超过某个阈值，就删除其中一个变量。

作为一般准则，我们应该保留那些与目标变量显示相当或高相关性的变量。
'''

# 并将变量保存在新的数据列（df）中。
df = train
'''
如下表所示，示例数据集中不存在高相关变量，但通常情况下，如果一对变量之间的相关性大于0.5-0.6，
那就应该考虑是否要删除一列了。
'''
df.corr()

# %%

from sklearn.ensemble import RandomForestRegressor

model = RandomForestRegressor(random_state=1, max_depth=10)
df = pd.get_dummies(df)
# 选择一个属性训练, 这里选择方差最大的OutCurrent. 可以看出相关性. 除了和自己,最大的就是InCurrent
model.fit(df, train.OutCurrent)

# 拟合模型后，绘制特征重要性图
features = df.columns
importances = model.feature_importances_
indices = np.argsort(importances)[-9:]  # top 10 features
plt.title('Feature Importances')
plt.barh(range(len(indices)), importances[indices], color='b', align='center')
plt.yticks(range(len(indices)), [features[i] for i in indices])
plt.xlabel('Relative Importance')
plt.show()

# %%

# 基于上图，我们可以手动选择最顶层的特征来减少数据集中的维度。
# 如果你用的是sklearn，可以直接使用SelectFromModel，它根据权重的重要性选择特征。
from sklearn.feature_selection import SelectFromModel

feature = SelectFromModel(model)
Fit = feature.fit_transform(df, train.OutCurrent)  #

# %% == 后向特征消除 =======================================================================

'''
先获取数据集中的全部n个变量，然后用它们训练一个模型。计算模型的性能。
在删除每个变量（n次）后计算模型的性能，即我们每次都去掉一个变量，用剩余的n-1个变量训练模型。
确定对模型性能影响最小的变量，把它删除。
重复此过程，直到不再能删除任何变量。
'''
from sklearn.linear_model import LinearRegression
from sklearn.feature_selection import RFE
from sklearn import datasets

lreg = LinearRegression()
rfe = RFE(lreg, 5)
rfe = rfe.fit_transform(df, train.OutCurrent)

# %% == 前向特征选择 =======================================================================

'''
这是我们上面看到的反向特征消除的相反过程。我们不是消除特征，而是试图找到提高模型性能的最佳特征。
该技术的工作原理如下：
    我们从一个功能开始。本质上，我们分别使用每个特征训练模型 n 次
    选择表现最佳的变量作为起始变量
    然后我们重复这个过程并一次添加一个变量。产生最大性能提升的变量被保留
    我们重复这个过程，直到模型的性能没有显着改善
'''
from sklearn.feature_selection import f_regression

ffs = f_regression(df, train.OutCurrent)
variable = []
for i in range(0, len(df.columns) - 1):
    if ffs[0][i] >= 10:
        variable.append(df.columns[i])

# %% == 因素分析 =======================================================================

import pandas as pd
import numpy as np
from glob import glob
import cv2  # 安装的是 opencv-python

images = [cv2.imread(file) for file in glob('data/*.jpg')]
images = np.array(images)
images.shape

# %%

# 正如你在上面看到的，它是一个 3 维数组。我们必须将其转换为一维，
# 因为所有即将推出的技术都只接受一维输入。为此，我们需要展平图像：
image = []
for i in range(0, 60000):
    img = images[i].flatten()
    image.append(img)
image = np.array(image)

# 现在让我们创建一个数据帧，其中包含每个图像中存在的每个像素的像素值，
# 以及它们对应的标签（对于标签，我们将使用train.csv文件）。
train = pd.read_csv("data/train.csv")  # 给出你的 train.csv 文件的完整路径
feat_cols = ['pixel' + str(i) for i in range(image.shape[1])]
df = pd.DataFrame(image, columns=feat_cols)
df['label'] = train['label']

# %%

# 现在我们将使用因子分析分解数据集：
from sklearn.decomposition import FactorAnalysis

FA = FactorAnalysis(n_components=3).fit_transform(df[feat_cols].values)

# n_components将决定转换数据中的因子数量。转换数据后，是时候将结果可视化了：
import matplotlib.pyplot as plt

plt.figure(figsize=(12, 8))
plt.title('Factor Analysis Components')
plt.scatter(FA[:, 0], FA[:, 1])
plt.scatter(FA[:, 1], FA[:, 2])
plt.scatter(FA[:, 2], FA[:, 0])

# %%

